<?php
// +----------------------------------------------------------------------
// | OneKeyAdmin [ Believe that you can do better ]
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2023 http://onekeyadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: MUKE <513038996@qq.com>
// +----------------------------------------------------------------------
namespace app\admin\controller;

use think\Image;
use think\facade\View;
use think\facade\Filesystem;
use think\exception\ValidateException;
use app\admin\BaseController;
use app\admin\model\Config;
use onekey\File as FileAddons;
use app\admin\model\File as FileModel;
/**
 * 文件
 */
class File extends BaseController
{
    /**
     * 显示资源列表
     */
    public function index()
    {
        if ($this->request->isPost()) {
            $input  = input('post.');
            $search = ['keyword','type'];
            $order  = [$input['prop'] => $input['order'], 'id' => 'asc'];
            $count  = FileModel::withSearch($search, $input)->count();
            $data   = FileModel::withSearch($search, $input)->order($order)->page($input['page'], 20)->select();
            return json(['status' => 'success', 'message' => '获取成功', 'data' => $data, 'count' => $count]);
        } else {
            return View::fetch();
        }
    }

    /**
     * 保存更新的资源
     */
    public function update()
    {
        if ($this->request->isPost()) {
            $input = input('post.');
            FileModel::where('id', $input['id'])->update($input);
            return json(['status' => 'success', 'message' => '修改成功']);
        }
    }

    /**
     * 下载文件
     */
    public function download()
    {
        $input = input();
        return download(public_path() . $input['url'], $input['title']);
    }

    /**
     * 支持上传大文件
     */
    public function upload()
    {
        $input        = input('post.');
        $uploadPath   = public_path().'upload/';
        $uploadFile   = $this->request->file('file');
        $originalName = $uploadFile->getOriginalName();
        $originalType = FileAddons::getType(config('upload.ext'),  $originalName);
        $chunkId      = empty($input['id']) ? md5(sha1_file($uploadFile).$input['size']) : $input['id'];
        $chunkIndex   = $input['index'];
        $chunkCount   = $input['count'];
        $chunkPath    = 'chunk/'.$chunkId.'/';
        if (empty($originalType)) {
            return json(['status' => 'error', 'message' => '类型不支持，在常规管理中可配置！']);
        }
        try {
            validate([ 'file' => ['fileSize' => config('upload.size')[$originalType], 'fileExt' => config('upload.ext')[$originalType]] ])->check(['file' => $uploadFile]);
        } catch (ValidateException $e) {
            return json(['status' => 'error', 'message' => $e->getMessage()]);
        }
        // 断点续传
        if ($chunkIndex == 1) {
            if (is_dir($uploadPath . $chunkPath)) {
               $oldChunkIndex = count(scandir($uploadPath . $chunkPath)) - 3; 
               if ($oldChunkIndex > 1) {
                    return json(['status' => 'success', 'message' => '断点续传', 'index' => $oldChunkIndex, 'id' => $chunkId]);
                }
            }
        }
        // 分片写入
        Filesystem::disk('public')->putFileAs($chunkPath, $uploadFile, $chunkIndex . '.tmp');
        if ($chunkIndex < $chunkCount) {
            return json(['status' => 'success', 'message' => '分片上传', 'index' => $chunkIndex, 'id' => $chunkId]);
        }
        // 分片检查
        for ($i = 1; $i <= $chunkCount; $i++) {
            if (! file_exists($uploadPath . $chunkPath . $i . '.tmp')) {
                return json(['status' => 'error', 'message' => '文件损坏，请重新上传']); 
            }
        }
        // 分片合并
        $filePath = $uploadPath . $originalType . '/' . date('Ymd')  . '/';
        if (! is_dir($filePath)) {
            mkdir($filePath, 0777, true);
        }
        $fileExt   = $uploadFile->getOriginalExtension() ? $uploadFile->getOriginalExtension() : substr(strrchr($originalName, '.'), 1);
        $fileName  = md5(microtime(true) . $originalName) . '.' . $fileExt;
        $fileWrite = @fopen($filePath . $fileName, "wb");
        if (flock($fileWrite, LOCK_EX)) {
            for ($i = 1; $i <= $chunkCount; $i++) {
                $uploadFile = $uploadPath . $chunkPath . $i . '.tmp';
                if (!$handle = @fopen($uploadFile, "rb")) {
                    break;
                }
                while ($buff = fread($handle, filesize($uploadFile))) {
                    fwrite($fileWrite, $buff);
                }
                @fclose($handle);
                @unlink($uploadFile); //删除分片
            }
            flock($fileWrite, LOCK_UN);
        }
        @fclose($fileWrite);
        // 存入数据库
        $save = FileModel::create([
            'title'       => $originalName,
            'type'        => $originalType,
            'size'        => $input['size'],
            'url'         => str_replace(public_path(), '/', $filePath . $fileName),
            'status'      => 1,
            'theme'       => theme(),
            'create_time' => $input['create_time'],
        ]);
        // 图片处理
        if ($originalType === "image" && $fileExt != 'ico' && $fileExt != 'gif') {
            // 封面图片
            thumbnail($save['url'],100,100);
            // 水印图片
            $watermark = $this->request->watermark;
            if (! empty($watermark)) {
                if ($watermark['open'] === 1) {
                    // 水印图片
                    $watermarkConfig = $this->request->watermark;
                    if (!empty($watermarkConfig)) {
                        if ($watermarkConfig['open'] === 1) {
                            $file     = str_replace('\/', '/', public_path() . $save->url);
                            $image    = Image::open($file);
                            $scale    = (int)$watermarkConfig['scale'] / 100;
                            $position = (int)$watermarkConfig['position'];
                            $opacity  = (int)$watermarkConfig['opacity'];
                            $height   = $image->height();
                            $width    = $image->width(); 
                            if ($watermarkConfig['type'] === 'image') {
                                $water = public_path() . 'upload/watermark.png';
                                if (is_file($water)) {
                                    if ($watermarkConfig['sizeType'] === 'scale') {
                                        // 按照比例
                                        $thumb = Image::open($water);
                                        $waterName  = pathinfo($save->url, PATHINFO_FILENAME);
                                        $waterThumb = str_replace('watermark', 'watermark_thumb', $water);
                                        $thumb->thumb($width*$scale, $height*$scale)->save($waterThumb);
                                        $image->water($waterThumb, $position, $opacity)->save($file);
                                        if (is_file($waterThumb)) {
                                            unlink($waterThumb);
                                        }
                                    } else {
                                        // 按实际大小
                                        $image->water($water, $position, $opacity)->save($file);
                                    }
                                }
                            } else {
                                $opacity    = 127 - (127 * $opacity / 100);
                                $dechex     = dechex($opacity);
                                $fontColor  = $watermarkConfig['fontColor'].$dechex;
                                $fontSize   = $watermarkConfig['sizeType'] === 'scale' ? $scale * ($width/2) : $watermarkConfig['fontSize'];
                                $fontFamily = public_path() . $watermarkConfig['fontFamily'];
                                $image->text($watermarkConfig['fontText'], $fontFamily, $fontSize, $fontColor, $position, 0, $watermarkConfig['fontAngle'])->save($file);
                            }
                        }
                    }
                }
            }
        }
        // 上传结束钩子
        event('UploadEnd', $save);
        return json(['status' => 'success', 'message' => '上传成功', 'data' => $save]);
    }
    
    /**
     * 支持上传大文件
     */
    public function fastUpload()
    {
        $uploadFile   = $this->request->file('file');
        $originalName = $uploadFile->getOriginalName();
        $originalSize = $uploadFile->getSize();
        $originalType = FileAddons::getType(config('upload.ext'),  $originalName);
        if (empty($originalType)) {
            return json(['status' => 'error', 'message' => '类型不支持，在常规管理中可配置！']);
        }
        // 验证
        try {
            validate([ 'file' => ['fileSize' => config('upload.size')[$originalType], 'fileExt' => config('upload.ext')[$originalType]] ])->check(['file' => $uploadFile]);
        } catch (ValidateException $e) {
            return json(['status' => 'error', 'message' => $e->getMessage()]);
        }
        // 上传
        $url = Filesystem::putFile($originalType, $uploadFile);
        $url = '/upload/' . str_replace('\\', '/', $url);
        // 存入数据库
        $save = FileModel::create([
            'title'       => $originalName,
            'type'        => $originalType,
            'size'        => $originalSize,
            'url'         => $url,
            'status'      => 1,
            'theme'       => theme(),
            'create_time' => date('Y-m-d H:i:s'),
        ]);
        // 图片处理
        $fileExt = $uploadFile->getOriginalExtension() ? $uploadFile->getOriginalExtension() : substr(strrchr($originalName, '.'), 1);
        if ($originalType === "image" && $fileExt != 'ico' && $fileExt != 'gif') {
            // 封面图片
            thumbnail($save['url'],100,100);
        }
        // 上传结束钩子
        event('UploadEnd', $save);
        return json(['status' => 'success', 'message' => '上传成功', 'data' => $save]);
    }

    /**
     * 放入回收站
     */
    public function recovery()
    {
        if ($this->request->isPost()) {
            $input = input('post.');
            FileModel::whereIn('id', $input['ids'])->update(['status' =>  0]);
            return json(['status' => 'success', 'message' => '回收成功']);
        }
    }

    /**
     * 彻底删除
     */
    public function delete()
    {
        if ($this->request->isPost()) {
            $input = input('post.');
            $list  = FileModel::whereIn('id', $input['ids'])->select();
            foreach ($list as $key => $val) {
                $file = str_replace('\/', '/', public_path() . $val->url);
                $name = pathinfo($val->url, PATHINFO_FILENAME);
                $thumb = str_replace($name, $name . '100x100', $file);
                if ($val->type === 'image') {
                    if(is_file($thumb)) unlink($thumb);
                }
                if(is_file($file)) unlink($file);
            }
            FileModel::whereIn('id', $input['ids'])->delete();
            return json(['status' => 'success', 'message' => '删除成功']);
        }
    }

    /**
     * 清空回收站
     */
    public function emptyTrash()
    {
        if ($this->request->isPost()) {
            $list = FileModel::where(['status' =>  0])->select();
            foreach ($list as $key => $val) {
                $file = str_replace('\/', '/', public_path() . $val->url);
                $name = pathinfo($val->url, PATHINFO_FILENAME);
                $thumb = str_replace($name, $name . '100x100', $file);
                if ($val->type === 'image') {
                    if(is_file($thumb)) unlink($thumb);
                }
                if(is_file($file)) unlink($file);
            }
            FileModel::where(['status' =>  0])->delete();
            return json(['status' => 'success', 'message' => '清空成功']);
        }
    }

    /**
     * 还原文件
     */
    public function reduction()
    {
        if ($this->request->isPost()) {
            FileModel::whereIn('id', input('ids'))->update(['status' =>  1]);
            return json(['status' => 'success', 'message' => '还原成功']);
        }
    }

    /**
     * 水印上传
     */
    public function watermarkUpload()
    {
        try {
            $file = $this->request->file('file');
            validate([ 'file' => ['fileSize' => config('upload.size')['image'], 'fileExt' => config('upload.ext')['image']] ])->check(['file' => $file]);
        } catch (ValidateException $e) {
            return json(['status' => 'error', 'message' => $e->getMessage()]);
        }
        Filesystem::putFileAs('/', $file, 'watermark.png');
        return json(['status' => 'success', 'message' => '上传成功', 'url' => '/upload/watermark.png']);
    }

    /**
     * 水印设置
     */
    public function watermarkConfig()
    {
        if ($this->request->isPost()) {
            $message = Config::setVal('watermark', '图片水印', input('post.value'));
            return json($message);
        }
    }
}
